#include "ecf2m.h"


#include <assert.h>
#include <memory.h>



void ECF2m_Add(const ECF2mWork *ec, const ECPoint *a, const ECPoint *b, ECPoint *c) {
	UInteger x, y;
	UInteger t[3]; // 临时变量

	UInteger k; // lambda
 
	// 求斜率
	if (!ECPoint_Equal(a, b)) {
		// k = (y2+y1)/(x2+x1)
		UInteger_BitModAdd(&a->y, &b->y, &ec->m, &k);
		UInteger_BitModAdd(&a->x, &b->x, &ec->m, t);
		UInteger_BitModDiv(&k, t, &ec->m, &k);
	} else {
		// k = x1 + y1/x1
		UInteger_BitModDiv(&a->y, &a->x, &ec->m, &k);
		UInteger_BitModAdd(&a->x, &k, &ec->m, &k);
	}

	// x = k^2 + k + x1 + x2 + a
	UInteger_BitModMul(&k, &k, &ec->m, &x);
	UInteger_BitModAdd(&x, &k, &ec->m, &x);
	UInteger_BitModAdd(&x, &a->x, &ec->m, &x);
	UInteger_BitModAdd(&x, &b->x, &ec->m, &x);
	UInteger_BitModAdd(&x, &ec->a, &ec->m, &x);
	
	// y = k(x1+x) + x + y1
	UInteger_BitModAdd(&a->x, &x, &ec->m, &y);
	UInteger_BitModMul(&k, &y, &ec->m, &y);
	UInteger_BitModAdd(&y, &x, &ec->m, &y);
	UInteger_BitModAdd(&y, &a->y, &ec->m, &y);

	UInteger_Copy(&x, &c->x);
	UInteger_Copy(&y, &c->y);
}

bool ECF2m_BelongTo(const ECF2mWork *ec, const UInteger *x, const UInteger *y) {
	UInteger t[2];

	UInteger_ModMul(x, x, &(ec->m), t);
	UInteger_ModMul(t, t, &(ec->m), t);

	UInteger_ModMul(x, &(ec->a), &(ec->m), t+1);
	UInteger_ModMul(t+1, t, &(ec->m), t);
	UInteger_ModMul(t, &(ec->b), &(ec->m), t);

	UInteger_ModMul(y, y, &(ec->m), t+1);

	return UInteger_Compare(t, t+1) == 0;
}

size_t ECF2m_ZA(const ECF2mWork *ec, uint8_t *za, size_t zasize) {
	size_t n = (ec->size+7)/8;

	if (za != NULL) {
		uint8_t t[n*2];
		UInteger_ToBytes(&(ec->a), t, n);
		UInteger_ToBytes(&(ec->b), t+n, n);

		memcpy(za, t, zasize>=n*2? n*2 : zasize);

	}

	return n*2;
}

void ECF2m_Initialize(ECF2mWork *ec, size_t size, const uint8_t *m, const uint8_t *a, const uint8_t *b) {
	assert(ec != NULL && m != NULL);

	ec->add = (EC_AddFcn) ECF2m_Add;
	ec->mul = (EC_MulFcn) EC_Mul;
	ec->on  = (EC_OnFcn)  ECF2m_BelongTo;
	ec->za  = (EC_ZAFcn)  ECF2m_ZA;
	ec->size = size;

	size_t n = (size+7) / 8;
	UInteger_FromBytes(&ec->m, m, n);
	UInteger_FromBytes(&ec->a, a, n);
	UInteger_FromBytes(&ec->b, b, n);
}
